#include "modbus.h"


Modbus::Modbus()
{
    modbusMaster = new QModbusRtuSerialMaster(this);
}

bool Modbus::connectToSlave(QString port, int baud)
{
    if (!modbusMaster)
        return false;
    if (modbusMaster->state() != QModbusDevice::ConnectedState)
    {
        modbusMaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter, port);
        //        modbusSlave->setConnectionParameter(QModbusDevice::SerialParityParameter,QSerialPort::NoParity);
        modbusMaster->setConnectionParameter(QModbusDevice::SerialParityParameter, QSerialPort::EvenParity);
        modbusMaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baud);
        modbusMaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, QSerialPort::Data8);
        modbusMaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, QSerialPort::OneStop);
        modbusMaster->setTimeout(1000);
        modbusMaster->setNumberOfRetries(3);
    }

    if (!modbusMaster->connectDevice())
    {
        return false;
    }
    else
    {
        return true;
    }
}

void Modbus::executeReadRequest(int RegisterType, int regAdress, int size, QVector<quint16> *values1)
{
    if (!modbusMaster) return;
    QModbusDataUnit *readRequest;
    QVector<quint16> values;
    values.push_back(1);
    if(RegisterType==0)
        readRequest = new QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, regAdress, size);
    else if(RegisterType==1)
        readRequest = new QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, regAdress, size);
    if (auto *reply = modbusMaster->sendReadRequest(*readRequest, 1))
    {
        if (!reply->isFinished())
        {
            connect(reply, &QModbusReply::finished, this, &Modbus::readReady);
            loop.exec();
        }
        else
            delete reply;
    }
    else
    {
        QDEBUG("Error: "+modbusMaster->errorString());
    }
    getCoisValue(values1);

}

void Modbus::executeWriteRequest(int RegisterType, int regAdress, QVector<quint16> values)
{
    QModbusDataUnit *writeRequest;
    if(RegisterType==0)
        writeRequest = new QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, regAdress, values);
    else if(RegisterType==1)
        writeRequest = new QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, regAdress, values);
    (*writeRequest).setValues(values);
    if (auto *reply = modbusMaster->sendWriteRequest(*writeRequest, 1))
    {
        if (!reply->isFinished())
        {
            //TODO: conncet signal finished to slot
            connect(reply, &QModbusReply::finished, this, &Modbus::writeRequestFinished);
        }
        else
        {
            reply->deleteLater();
        }
    }
    else
    {
        QDEBUG("Error: "+reply->errorString());
    }
}

void Modbus::readReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply) return;
    if (reply->error() == QModbusDevice::NoError)
    {
        const QModbusDataUnit modbusDataUnit = reply->result();
        for (uint i = 0; i < modbusDataUnit.valueCount(); i++)
        {
//            qDebug () << "Value: " << modbusDataUnit.value(i);
            //            emit coisValue((bool)modbusDataUnit.value(i));
            m_coisValue.push_back(modbusDataUnit.value(i));
        }
    }
    else if (reply->error() == QModbusDevice::ProtocolError)
    {
        QDEBUG("Protocol error: "+reply->errorString());
    }
    else
    {
        QDEBUG("Error: "+reply->errorString());
    }
    loop.quit();
}

void Modbus::writeRequestFinished()
{
    auto reply  = qobject_cast<QModbusReply *>(sender());
    if (!reply) return;
    if (reply->error() == QModbusDevice::ProtocolError)
    {
        QDEBUG("Protocol error:: "+reply->errorString());
    }
    else if (!reply->error() == QModbusDevice::NoError)
    {
        QDEBUG("Other error: "+reply->errorString());
    }
    else
    {
        QDEBUG("Send request status: ok ");
    }
}

bool Modbus::isConnect()
{
    if (modbusMaster->state() != QModbusDevice::ConnectedState)
    {
        return false;
    }
    else
        return true;
}

bool Modbus::disconnectToSlave()
{
    if (!modbusMaster)
        return false;
    if (modbusMaster->state() == QModbusDevice::ConnectedState)
    {
        modbusMaster->disconnectDevice();
    }
    return true;
}

bool Modbus::getCoisValue(QVector<quint16> *value)
{
    *value = m_coisValue;
    m_coisValue.clear();
    return true;
}











